package com.yanghui.core

import com.yanghui.data.AbstractSmallestItem
import com.yanghui.data.ChangedSmallestItem
import com.yanghui.data.LogicExpression
import java.util.*
import kotlin.collections.LinkedHashMap
import kotlin.math.log
import kotlin.math.pow

object QMCore {

    const val ACCURATE = 0
    const val APPROXIMATE = 1

    fun qmReduction(logicExpression: LogicExpression, type: Int = APPROXIMATE, varList: LinkedList<Char>): String {
        var result = ""
        val halfResultSmallestItemList = LinkedList<ChangedSmallestItem>()
        // 分区表
        val expressionSplit = LinkedList<LinkedList<ChangedSmallestItem>>()
        repeat(logicExpression.varNum + 1) {
            expressionSplit.add(LinkedList())
        }
        logicExpression.smallestItemList.forEach {
            val changedItem = ChangedSmallestItem(it)
            expressionSplit[changedItem.getHighNum()].add(changedItem)
        }
        for (i in 1..logicExpression.varNum) {
            // 初始化新的分区表
            val changedSmallestItemSet = LinkedList<ChangedSmallestItem>()
            val newExpressionSplit = LinkedList<LinkedList<ChangedSmallestItem>>()
            repeat(logicExpression.varNum + 1 - i) {
                newExpressionSplit.add(LinkedList())
            }
            val canMergeMap = LinkedHashMap<ChangedSmallestItem, Boolean>()
            expressionSplit.forEach {
                it.forEach {
                    canMergeMap[it] = false
                }
            }
            // 前后两两循环比较
            for (j in 0 until expressionSplit.size - 1) {
                expressionSplit[j].forEach { item0 ->
                    expressionSplit[j + 1].forEach { item1 ->
                        item0.checkMerge(item1)?.let {
                            changedSmallestItemSet.add(it)
                            canMergeMap[item0] = true
                            canMergeMap[item1] = true
                        }
                    }
                }
            }
            canMergeMap.forEach { (k, v) ->
                if (!v) {
                    var canJoin = true
                    halfResultSmallestItemList.forEach {
                        if (k.equal(it))
                            canJoin = false
                    }
                    if (canJoin)
                        halfResultSmallestItemList.add(k)
                }
            }
            changedSmallestItemSet.forEach {
                newExpressionSplit[it.getHighNum()].add(it)
            }
            if (changedSmallestItemSet.size == 0)
                break
            expressionSplit.clear()
            expressionSplit.addAll(newExpressionSplit)
        }
        // 暴力尝试方法
        val resultSmallestItemList = LinkedList<ChangedSmallestItem>()

        if (type == APPROXIMATE) {
            val smallestItemListFilledMap = LinkedHashMap<Long, Boolean>()
            logicExpression.smallestItemList.forEach {
                smallestItemListFilledMap[AbstractSmallestItem.logicListToInitNum(
                    logicExpression.varNum, it.varValueList
                )] = false
            }
            while (true) {
                var end = true
                smallestItemListFilledMap.values.forEach {
                    if (!it)
                        end = false
                }
                if (end) {
                    break
                }
                halfResultSmallestItemList.sortByDescending {
                    var cnt = 0
                    it.enableVarNumList.forEach { num ->
                        if (!smallestItemListFilledMap[num]!!)
                            cnt++
                    }
                    cnt
                }
                halfResultSmallestItemList.removeFirst().let {
                    it.enableVarNumList.forEach { num ->
                        smallestItemListFilledMap[num] = true
                    }
                    resultSmallestItemList.add(it)
                }
            }
        } else {
            TODO("这玩意你觉得穷举2^n能算得完？")
        }
        resultSmallestItemList.forEachIndexed { index, item ->
            result += (item.toString(varList))
            if (index != resultSmallestItemList.size - 1)
                result += ("+")
        }
        return result
    }
}

fun main(args: Array<String>) {
    var logSmallestItem = true
    if ("--table" in args) {
        logSmallestItem = true
    }
    val logic = LogicExpression(readLine()!!)
    println(QMCore.qmReduction(logic, QMCore.APPROXIMATE, logic.varNameList))

    if (logSmallestItem) {
        println("\nTruth Table")
        repeat(logic.varNum) {
            print("${logic.varNameList[it]} ")
        }
        println("Result")
        for (i in 0 until 2.0.pow(logic.varNum).toLong()) {
            repeat(logic.varNum) {
                if ((i ushr it) and 1 == 1L) {
                    print("1 ")
                } else
                    print("0 ")
            }
            if (i in logic.smallestIDList)
                println("1")
            else
                println("0")
        }
        print("\nm${logic.smallestIDList}")
    }
}